﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using System.Threading;
using CommonLibrary.Other;
using Microsoft.VisualBasic.FileIO;
using SearchOption = Microsoft.VisualBasic.FileIO.SearchOption;

namespace CommonLibrary
{
    public static class FileClass
    {
        /// <summary>
        /// 追加文本，写日志
        /// </summary>
        /// <param name="in_file"></param>
        /// <param name="msg"></param>
        /// <param name="encoding"></param>
        public static void AppendText(string in_file, string msg, Encoding encoding)
        {
            Mutex m = new Mutex(false, in_file.ClMD5String());

            try
            {
                m.WaitOne();//等待其它m释放

                string dir = Regex.Match(in_file, @".*\\", System.Text.RegularExpressions.RegexOptions.IgnoreCase).ToString();
                if (Directory.Exists(dir) == false)
                {
                    Directory.CreateDirectory(dir);
                }

                File.AppendAllText(in_file, msg, (encoding ?? Encoding.UTF8));
            }
            finally
            {
                m.ReleaseMutex();
                m.Close();
            }
        }


        /// <summary>
        /// 写文本
        /// </summary>
        /// <param name="in_file"></param>
        /// <param name="msg"></param>
        /// <param name="encoding"></param>
        public static void WriteFile(string in_file, string msg, Encoding encoding)
        {
            if (File.Exists(in_file))
            {
                File.Delete(in_file);
            }
            AppendText(in_file, msg, encoding);
        }

        /// <summary>
        /// 写文本
        /// </summary>
        /// <param name="in_file"></param>
        /// <param name="msg"></param>
        /// <param name="encoding"></param>
        public static void WriteFile(string in_file, string msg)
        {
            WriteFile(in_file, msg, Encoding.UTF8);
        }

        /// <summary>
        /// 读取文件内容
        /// </summary>
        /// <param name="in_file"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string ReadFile(string in_file, Encoding encoding)
        {
            Mutex m = new Mutex(false, in_file.Trim().ToUpper().ClMD5String());

            try
            {
                m.WaitOne();//等待其它m释放

                StreamReader reader = new StreamReader(in_file, encoding);
                string str = reader.ReadToEnd();
                reader.Close();

                return str;
            }
            finally
            {
                m.ReleaseMutex();
                m.Close();
            }

        }

        /// <summary>
        /// 读取文件内容
        /// </summary>
        /// <param name="in_file"></param>
        /// <returns></returns>
        public static string ReadFile(string in_file)
        {
            return ReadFile(in_file, Encoding.UTF8);
        }


        /// <summary>
        /// 生成bat文件，支持中文
        /// </summary>
        /// <param name="in_file"></param>
        /// <param name="in_cmd"></param>
        public static void CreateBatFile(string in_file, string in_cmd)
        {
            using (FileStream writer = new FileStream(in_file, FileMode.OpenOrCreate))
            {
                byte[] bytes = ASCIIEncoding.Default.GetBytes(in_cmd);
                writer.Write(bytes, 0, bytes.Length);
            }
        }


        #region Log

        public static string LogPath = System.Configuration.ConfigurationManager.AppSettings["LogPath"];
        public static string LogType = System.Configuration.ConfigurationManager.AppSettings["LogType"];
        //有LogFile以LogFile为准,没有则按LogPath+LogType+date.xml
        public static string LogFile = System.Configuration.ConfigurationManager.AppSettings["LogFile"];


        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="xmlFile"></param>
        /// <param name="msg"></param>
        /// <param name="trace"></param>
        public static void Log(string xmlFile, string msg, string trace)
        {
            #region OpenXml

            Func<string, DataTable> OpenXml = (in_XmlFile) =>
            {
                try
                {
                    DataTable dtXml = new DataTable("Log");

                    dtXml.Columns.Add("DateTime", typeof(string));
                    dtXml.Columns.Add("Message", typeof(string));
                    dtXml.Columns.Add("StackTrace", typeof(string));

                    dtXml.PrimaryKey = new DataColumn[] { dtXml.Columns["DateTime"] };

                    if (File.Exists(in_XmlFile))
                    {
                        try
                        {
                            dtXml.ReadXml(in_XmlFile);
                            return dtXml;
                        }
                        catch
                        {
                            File.Delete(in_XmlFile);
                        }
                    }

                    dtXml.WriteXml(in_XmlFile);
                    return dtXml;
                }
                catch (Exception err)
                {
                    LogTxt(err);
                    throw;
                }
            };

            #endregion

            Mutex m = new Mutex(false, xmlFile.Trim().ToUpper().ClMD5String());

            try
            {
                m.WaitOne();//等待其它m释放

                Thread.Sleep(10);
                FileInfo fileInfo = new FileInfo(xmlFile);
                if (Directory.Exists(fileInfo.Directory.FullName) == false)
                {
                    Directory.CreateDirectory(fileInfo.Directory.FullName);
                }
                DateTime dateTime = DateTime.Now;

                using (DataTable dt = OpenXml(xmlFile))
                {
                    DataRow row = dt.NewRow();
                    row[0] = dateTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
                    row[1] = msg;
                    row[2] = trace;
                    dt.Rows.Add(row);

                    dt.WriteXml(xmlFile);
                }
            }
            finally
            {
                m.ReleaseMutex();
                m.Close();
            }
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="trace"></param>
        public static void Log(string msg, string trace)
        {
            DateTime dateTime = DateTime.Now;
            string tmpPath = @"D:\Log\";
            if (LogPath.ClIsNullOrWhiteSpace() == false)
            {
                tmpPath = LogPath;
                if (tmpPath.Substring(tmpPath.Length - 1) != @"\")
                {
                    tmpPath += @"\";
                }
            }
            Directory.CreateDirectory(tmpPath);

            string tmpType = "PublicLog";
            if (LogType.ClIsNullOrWhiteSpace() == false)
            {
                tmpType = LogType;
            }

            string xmlFile = tmpPath + tmpType + "_" + dateTime.ToString("yyyy_MM_dd") + ".xml";
            if (string.IsNullOrWhiteSpace(LogFile) == false)
            {
                xmlFile = LogFile;
            }

            Log(xmlFile, msg, trace);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="msg"></param>
        public static void Log(string msg)
        {
            Log(msg, "");
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="err"></param>
        public static void Log(this Exception err)
        {
            Log(err.Message, err.StackTrace);
        }




        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="msg"></param>
        public static void LogTxt(string msg)
        {
            Mutex m = new Mutex(false, "62F1B3A7-17D0-4663-94CF-56406F637121");

            try
            {
                m.WaitOne();//等待其它m释放

                Thread.Sleep(10);
                DateTime dateTime = DateTime.Now;
                string tmpPath = @"D:\Log\";
                if (LogPath.ClIsNullOrWhiteSpace() == false)
                {
                    tmpPath = LogPath;
                    if (tmpPath.Substring(tmpPath.Length - 1) != @"\")
                    {
                        tmpPath += @"\";
                    }
                }
                Directory.CreateDirectory(tmpPath);

                string tmpType = "PublicLog";
                if (LogType.ClIsNullOrWhiteSpace() == false)
                {
                    tmpType = LogType;
                }

                string txtFile = tmpPath + tmpType + "_" + dateTime.ToString("yyyy_MM_dd") + ".txt";
                if (string.IsNullOrWhiteSpace(LogFile) == false)
                {
                    txtFile = LogFile + ".txt";
                }

                using (StreamWriter sw = new StreamWriter(txtFile, true, Encoding.UTF8))
                {
                    sw.Write(dateTime.ToString("yyyy-MM-dd HH:mm:ss") + " ：" + msg + Environment.NewLine);
                }
            }
            finally
            {
                m.ReleaseMutex();
                m.Close();
            }
        }

        public static void LogTxt(Exception err)
        {
            LogTxt(err.Message + Environment.NewLine + err.StackTrace + Environment.NewLine);
        }

        #endregion






        /// <summary>
        /// 获取临时文件
        /// </summary>
        /// <param name="in_Extension"></param>
        /// <returns></returns>
        public static string GetTempFile(string in_Extension)
        {
            return Path.GetTempPath() + DateTime.Now.ToString("yyyy.MM.dd.HH.mm.ss.fff") + Guid.NewGuid().ToString().Replace("-", ".") + in_Extension;
        }

        /// <summary>
        /// 获取临时文件
        /// </summary>
        /// <returns></returns>
        public static string GetTempFile()
        {
            return GetTempFile(".txt");
        }

        /// <summary>
        /// 获取程序全名
        /// </summary>
        /// <returns></returns>
        public static string GetExecutablePath()
        {
            return Environment.CommandLine.Replace(@"""", @"");
        }

        /// <summary>
        /// 获取程序起始路径
        /// </summary>
        /// <returns></returns>
        public static string GetStartupPath()
        {
            return Environment.CommandLine.Substring(1, Environment.CommandLine.LastIndexOf(@"\"));
        }

        /// <summary>
        /// 补最后斜杠
        /// </summary>
        /// <param name="in_dir"></param>
        /// <returns></returns>
        public static string ClSetLastXieGang(this string in_dir)
        {
            return Regex.Match(in_dir, @".*[^\\$]", RegexOptions.IgnoreCase).ToString() + @"\";
        }




        /// <summary>
        /// 删除文件到垃圾箱
        /// </summary>
        /// <param name="in_path"></param>
        /// <returns></returns>
        public static bool DeleteFileToRecycleBin(string in_file)
        {
            try
            {
                FileSystem.DeleteFile(in_file, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                return true;
            }
            catch (Exception err)
            {
                Log(err);
                throw;
            }
        }

        /// <summary>
        /// 删除文件夹到垃圾箱
        /// </summary>
        /// <param name="in_path"></param>
        /// <returns></returns>
        public static bool DeleteDirectoryToRecycleBin(string in_path)
        {
            try
            {
                FileSystem.DeleteDirectory(in_path, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                return true;
            }
            catch (Exception err)
            {
                Log(err);
                throw;
            }
        }

        /// <summary>
        /// 复制文件夹
        /// </summary>
        /// <param name="in_frPath"></param>
        /// <param name="in_toPath"></param>
        /// <returns></returns>
        public static bool CopyDirectory(string in_frPath, string in_toPath)
        {
            try
            {
                FileSystem.CopyDirectory(in_frPath, in_toPath, true);
                return true;
            }
            catch (Exception err)
            {
                Log(err);
                throw;
            }
        }

        /// <summary>
        /// 移动文件夹
        /// </summary>
        /// <param name="in_frPath"></param>
        /// <param name="in_toPath"></param>
        /// <returns></returns>
        public static bool MoveDirectory(string in_frPath, string in_toPath)
        {
            try
            {
                FileSystem.MoveDirectory(in_frPath, in_toPath, true);
                return true;
            }
            catch (Exception err)
            {
                Log(err);
                throw;
            }
        }





        /// <summary>
        /// 备份文件夹
        /// </summary>
        /// <param name="in_FromDir"></param>
        /// <param name="in_ToDir"></param>
        /// <param name="in_IncludeChild"></param>
        /// <returns></returns>
        public static bool BackupDirectory(string in_FromDir, string in_ToDir, bool in_IncludeChild)
        {
            string sourceDir = Regex.Match(in_FromDir, @".*[^\\$]", System.Text.RegularExpressions.RegexOptions.IgnoreCase).ToString() + @"\";
            string targetDir = Regex.Match(in_ToDir, @".*[^\\$]", System.Text.RegularExpressions.RegexOptions.IgnoreCase).ToString() + @"\";
            string bakDir = targetDir + @"（备份文件夹，不要删除）8E65BD49-B060-4A97-A4B0-C3FC80F8F26F\";


            Mutex m = new Mutex(false, (in_FromDir.ToUpper() + "_" + in_ToDir.ToUpper()).ClMD5String());//false：是否要等其它调用的进程结束！！！
            try
            {
                m.WaitOne();//等待其它m释放

                #region 创建目录
                //targetDir
                if (!Directory.Exists(targetDir))
                {
                    try
                    {
                        Directory.CreateDirectory(targetDir);
                    }
                    catch (Exception err)
                    {
                        err.Log();
                        return false;
                    }
                }

                //bakDir
                if (!Directory.Exists(bakDir))
                {
                    try
                    {
                        Directory.CreateDirectory(bakDir);
                    }
                    catch (Exception err)
                    {
                        err.Log();
                        return false;
                    }
                }

                //timeDir
                DateTime dtNow = DateTime.Now;

                string timeDir = bakDir + dtNow.ClToStringBackupFormat() + @"\";

                #endregion


                #region 获取源文件夹所有文件
                List<string> listSourceFiles = new List<string>();

                if (in_IncludeChild == false)
                {
                    string[] tmpFiles = Directory.GetFiles(sourceDir, "*.*", System.IO.SearchOption.TopDirectoryOnly);
                    List<string> listTmp = new List<string>(tmpFiles);
                    listSourceFiles.AddRange(listTmp);
                }
                else
                {
                    string[] tmpFiles = Directory.GetFiles(sourceDir, "*.*", System.IO.SearchOption.TopDirectoryOnly);
                    List<string> listTmp = new List<string>(tmpFiles);
                    listSourceFiles.AddRange(listTmp);


                    string[] tmpDirs = Directory.GetDirectories(sourceDir, "*.*", System.IO.SearchOption.TopDirectoryOnly);
                    foreach (string tmpDir in tmpDirs)
                    {
                        try
                        {
                            tmpFiles = Directory.GetFiles(tmpDir, "*.*", System.IO.SearchOption.AllDirectories);
                            listTmp = new List<string>(tmpFiles);
                            listSourceFiles.AddRange(listTmp);

                        }
                        catch (Exception err)
                        {
                            //获取System Volume Information会出错，跳过错误
                            err.Log();
                        }
                    }

                }
                #endregion


                Thread[] threads = new Thread[8];//初始化工作线程
                foreach (string sourceFile in listSourceFiles)
                {
                    int threadIndex = SystemHelper.GetFreeThread(threads);//获取空闲线程

                    FileClassCopyFile c = new FileClassCopyFile(sourceFile, sourceDir, targetDir, timeDir);//处理当前目录下的每一个文件
                    threads[threadIndex] = new Thread(new ThreadStart(c.CopyFile));
                    threads[threadIndex].IsBackground = true;
                    threads[threadIndex].Start();
                }

                SystemHelper.CheckThreadComplete(threads);

                if (FileClassCopyFile.DeleteFile(targetDir, sourceDir, targetDir, timeDir, in_IncludeChild) == false)
                {
                    //删除targetDir比sourceDir多的文件
                    return false;
                }
            }
            catch (Exception ex)
            {
                ex.Log();
            }
            finally
            {
                m.ReleaseMutex();
                m.Close();
            }

            return true;
        }

        /// <summary>
        /// 备份文件夹
        /// </summary>
        /// <param name="in_FromDir"></param>
        /// <param name="in_ToDir"></param>
        /// <returns></returns>
        public static bool BackupDirectory(string in_FromDir, string in_ToDir)
        {
            return BackupDirectory(in_FromDir, in_ToDir, true);
        }





        /// <summary>
        /// ClSaveStreamToFile
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="filename"></param>
        public static void ClSaveStreamToFile(this Stream stream, string filename)
        {
            Action<Stream, Stream> WriteStream = delegate(Stream from, Stream to)
            {
                for (int a = from.ReadByte(); a != -1; a = from.ReadByte())
                {
                    to.WriteByte((byte)a);
                }
            };

            using (Stream destination = File.Create(filename))
            {
                WriteStream(stream, destination);
            }
        }


        /// <summary>
        /// 按时间排序返回文件列表
        /// </summary>
        /// <param name="path"></param>
        /// <param name="searchPattern"></param>
        /// <param name="searchOption"></param>
        /// <param name="sortOption"></param>
        /// <returns></returns>
        public static FileInfo[] GetFiles(string path, string searchPattern, System.IO.SearchOption searchOption, SortOption sortOption)
        {
            DirectoryInfo di = new DirectoryInfo(path);
            FileInfo[] fis = di.GetFiles(searchPattern, searchOption);
            Array.Sort(fis, new SortFile(sortOption));
            return fis;
        }


        /// <summary>
        /// 流转换为字符串
        /// </summary>
        /// <param name="in_stream"></param>
        /// <returns></returns>
        public static string ClToString(this Stream in_stream)
        {
            in_stream.Position = 0;

            using (StreamReader sr = new StreamReader(in_stream))
            {
                return sr.ReadToEnd();
            }
        }

        /// <summary>
        /// 字符串转换为流
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static Stream ClToStream(this string in_str)
        {
            MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(in_str));
            return stream;
        }


        /// <summary>
        /// 目录内文件、子目录重命名
        /// </summary>
        /// <param name="in_path"></param>
        /// <param name="in_old"></param>
        /// <param name="in_new"></param>
        /// <param name="in_IncludeChild"></param>
        public static void RenameFile(string in_path, string in_old, string in_new, bool in_IncludeChild)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(in_path);

            FileInfo[] fileInfos = directoryInfo.GetFiles("*.*", System.IO.SearchOption.TopDirectoryOnly);
            foreach (FileInfo fileInfo in fileInfos)
            {
                string oldFileName = fileInfo.FullName;
                string newFileName = fileInfo.FullName.Replace(in_old, in_new);
                if (oldFileName != newFileName)
                {
                    fileInfo.MoveTo(newFileName);
                }
            }



            DirectoryInfo[] directoryInfos = directoryInfo.GetDirectories("*.*", System.IO.SearchOption.TopDirectoryOnly);
            foreach (DirectoryInfo info in directoryInfos)
            {
                string oldDirName = info.FullName;
                string newDirName = info.FullName.Replace(in_old, in_new);
                if (oldDirName != newDirName)
                {
                    info.MoveTo(newDirName);
                }

                if (in_IncludeChild)
                {
                    RenameFile(newDirName, in_old, in_new, in_IncludeChild);
                }
            }

        }

        /// <summary>
        /// 目录内文件、子目录重命名
        /// </summary>
        /// <param name="in_path"></param>
        /// <param name="in_old"></param>
        /// <param name="in_new"></param>
        public static void RenameFile(string in_path, string in_old, string in_new)
        {
            RenameFile(in_path, in_old, in_new, true);
        }


        /// <summary>
        /// 目录内文件替换名字
        /// </summary>
        /// <param name="in_path"></param>
        /// <param name="in_old"></param>
        /// <param name="in_new"></param>
        /// <param name="in_IncludeChild"></param>
        public static void ReplaceFile(string in_path, string in_old, string in_new, bool in_IncludeChild)
        {
            string[] dirs = Directory.GetDirectories(in_path, ".svn", System.IO.SearchOption.AllDirectories);
            foreach (string dir in dirs)
            {
                string cmd = "rd " + dir.ClShortPathName() + " /s /q";
                cmd.ClRunAsDos("");
            }


            System.IO.SearchOption searchOption = System.IO.SearchOption.TopDirectoryOnly;
            if (in_IncludeChild)
            {
                searchOption = System.IO.SearchOption.AllDirectories;
            }
            string[] files = Directory.GetFiles(in_path, "*.*", searchOption);
            foreach (string txfile in files)
            {
                Encoding encoding = EncodingType.GetType(txfile);
                string txt = txfile.ClReadFile(encoding);
                txt = txt.Replace(in_old, in_new);
                txfile.ClWriteFile(txt, encoding);
            }
        }

        /// <summary>
        /// 目录内文件替换名字
        /// </summary>
        /// <param name="in_path"></param>
        /// <param name="in_old"></param>
        /// <param name="in_new"></param>
        public static void ReplaceFile(string in_path, string in_old, string in_new)
        {
            ReplaceFile(in_path, in_old, in_new, true);
        }
    }










}
